package cool.houge.pig;

import java.util.LinkedList;
import java.util.List;
import lombok.Value;

/**
 * 业务码异常.
 *
 * @author KK (kzou227@qq.com)
 */
public class BizCodeException extends RuntimeException {

  private final BizError bizError;
  private List<NameValue> contextValues;

  /** @param bizError */
  public BizCodeException(BizError bizError) {
    this.bizError = bizError;
  }

  /**
   * @param bizError
   * @param message
   */
  public BizCodeException(BizError bizError, String message) {
    super(message);
    this.bizError = bizError;
  }

  /**
   * @param bizError
   * @param cause
   */
  public BizCodeException(BizError bizError, Throwable cause) {
    super(cause);
    this.bizError = bizError;
  }

  /**
   * @param bizError
   * @param message
   * @param cause
   */
  public BizCodeException(BizError bizError, String message, Throwable cause) {
    super(message, cause);
    this.bizError = bizError;
  }

  /** 返回业务错误. */
  public BizError getBizError() {
    return bizError;
  }

  /**
   * @param name
   * @param value
   * @return
   */
  public BizCodeException putContextValue(String name, Object value) {
    if (contextValues == null) {
      contextValues = new LinkedList<>();
    }
    this.contextValues.add(new NameValue(name, value));
    return this;
  }

  /**
   * 返回格式化的错误描述.
   *
   * @return 错误描述
   */
  @Override
  public String getMessage() {
    return getFormattedMessage(super.getMessage());
  }

  /** 返回原始的消息. */
  public String getRawMessage() {
    return super.getMessage();
  }

  /**
   * 返回格式化的错误描述.
   *
   * @return 错误描述
   */
  @Override
  public String toString() {
    return getFormattedMessage(super.getMessage());
  }

  private String getFormattedMessage(final String baseMessage) {
    final StringBuilder builder = new StringBuilder(256);
    if (baseMessage != null) {
      builder.append(baseMessage);
    }
    builder
        .append("\n\t[code=")
        .append(bizError.code())
        .append(", message=")
        .append(bizError.message())
        .append(']');

    if (contextValues != null) {
      builder.append("\nContext Values:\n");

      int i = 0;
      for (final NameValue cv : contextValues) {
        builder.append("\t[");
        builder.append(++i);
        builder.append(':');
        builder.append(cv.getName());
        builder.append("=");
        final Object value = cv.getValue();
        if (value == null) {
          builder.append("null");
        } else {
          try {
            builder.append(value);
          } catch (final Exception e) {
            builder.append("Exception thrown on toString(): ").append(e.getMessage());
          }
        }
        builder.append("]\n");
      }
      builder.append("---------------------------------");
    }
    return builder.toString();
  }

  @Value
  public static final class NameValue {

    /** 名字. */
    private String name;
    /** 值. */
    private Object value;
  }
}
